package com.im.chen.unionpay;

import android.Manifest;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Looper;
import android.support.v4.content.ContextCompat;
import android.widget.EditText;
import android.widget.Toast;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class PayUtilsNoUI {

    private static final String TAG = "PayUtils";
    private final static String remote_genCodeUrl = "http://115.29.246.59/dxsp/woread/smscode.do";
    private static final String remote_verifyCodeUrl = "http://115.29.246.59/dxsp/woread/ordersms.do";
    private static final String remote_productsUrl = "http://115.29.246.59/dxsp/woread/product.do";
    private final static String local_genCodeUrl = "http://192.168.1.38:8080/unicompay/smscode.do";
    private static final String local_verifyCodeUrl = "http://192.168.1.38:8080/unicompay/ordersms.do";
    private static final String local_productsUrl = "http://192.168.1.38:8080/unicompay/product.do";
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    public static ProgressDialog progressDialog;
    private static Context mContext;
    private static OnBilling mOnBillingCallback;
    public static int mServerPoint = 0;
    private static String productsUrl;
    private static String genCodeUrl;
    private static String verifyCodeUrl;

    static EditText etSmsCode;
    private static boolean isInit = false;
    private static boolean waitCode = true;
    private static String smsCode = null;
    private static boolean showUI = true;
    private static String mCurrentOSN = null;
    private static int waitCodeTimeOut= 5 * 1000;
    private static String phoneRegx="0?(13|14|15|17|18|19)[0-9]{9}";

    enum StatusTypes{
        NORMAL(0),
        SMSCODEERRO(1),
        GETSMSCODEFAILED(2),
        NETWORKEXCEPTION(3),
        ORDERERROR(4),
        BILLINGFAILED(5),
        READMESSAGEDENIED(6),
        PHONENUMBERERROR(7);
        int type;

        StatusTypes(int type){
            this.type=type;
        }
    }

    public static void init(Context context) {
        mContext = context;
        init(context, null, 0);
    }

    public static void init(Context context, int serverPoint) {
        init(context, null, serverPoint);
    }

    public static void init(Context context, JSONObject jsonConfig) {
        init(context, jsonConfig, 0);
    }

    public static void init(Context context, JSONObject jsonConfig, int serverPoint) {
        if (!isInit) {
            mContext = context;
            mServerPoint = serverPoint;
            changeServer(mServerPoint);
            autoFillCode(jsonConfig);
        }
        isInit = true;
    }

    private static void autoFillCode(JSONObject jsonConfig) {
        SmsObserver smsObserver = new SmsObserver(null, mContext, jsonConfig, new SmsObserver.OnReceive() {
            @Override
            public void onFailed(String result) {
                waitCode = false;
                LogUtil.e(TAG, "获取验证码失败：" + result);
            }

            @Override
            public void onSuccess(String result) {
                waitCode = false;
                smsCode = result;
                LogUtil.d(TAG, "获取验证码成功：" + result);
            }
        });
        mContext.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, smsObserver);
    }

    /**
     * change server
     *
     * @param serverPoint
     */
    public static void changeServer(int serverPoint) {
        switch (serverPoint) {
            case 0:
                productsUrl = local_productsUrl;
                genCodeUrl = local_genCodeUrl;
                verifyCodeUrl = local_verifyCodeUrl;
                break;
            case 1:
                productsUrl = remote_productsUrl;
                genCodeUrl = remote_genCodeUrl;
                verifyCodeUrl = remote_verifyCodeUrl;
                break;
            default:
                productsUrl = local_productsUrl;
                genCodeUrl = local_genCodeUrl;
                verifyCodeUrl = local_verifyCodeUrl;
                break;
        }
    }

    /**
     * generator order
     *
     * @param cid channel id
     * @param pid parch id
     */
    public static void genOrderAndSendSms(String cid, String pid, String phone, Callback callback) throws IOException {
        String paramStr = "?cid=" + cid + "&pid=" + pid + "&phone=" + phone;
        get(genCodeUrl + paramStr, callback);
    }

    public static void verifyCode(String osn, String smsCode, Callback callback) throws IOException {
        String paramStr = "?osn=" + osn + "&smscode=" + smsCode;
        get(verifyCodeUrl + paramStr, callback);
    }

    public static void getProducts(String cid, Callback callback) throws IOException {
        String paramStr = "?cid=" + cid;
        get(productsUrl + paramStr, callback);
    }

    /**
     * 基础的get方法
     *
     * @param url
     * @param callback
     * @throws IOException
     */
    private static void get(String url, Callback callback) throws IOException {
        LogUtil.d(TAG, ">>>>>>>>>>>>>>>> get: " + url);
//        showProgress(mContext, "请求中："+url);
        OkHttpClient client = new OkHttpClient();
        OkHttpClient clientWithTimeOut = client.newBuilder().readTimeout(30, TimeUnit.SECONDS).build();
        final Request request = new Request.Builder().url(url).build();
        clientWithTimeOut.newCall(request).enqueue(callback);
    }

    /**
     * post 方法
     *
     * @param url
     * @param json
     * @return
     * @throws IOException
     */
    private static String post(String url, String json) throws IOException {
        LogUtil.d(TAG, ">>>>>>>>>>>>>>>> post: " + url);
//        showProgress(mContext, "请求中："+url);
        OkHttpClient client = new OkHttpClient().newBuilder().readTimeout(30, TimeUnit.SECONDS).build();
        RequestBody body = RequestBody.create(JSON, json);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        Response response = client.newCall(request).execute();
        return response.body().string();
    }


    /**
     * buy anything by this method
     *
     * @param cid         channel id
     * @param pid         product id
     * @param phoneNumber phone number
     * @param callback    BuyCallback function
     * @throws Exception Exception
     */
    public static void billing(String cid, String pid, String phoneNumber, OnBilling callback) throws Exception {
        mOnBillingCallback = callback;
        genOrderAndSendSms(cid, pid, phoneNumber);
    }

    //third part

    /**
     * Get all products by channel id
     *
     * @param cid channel id
     * @throws IOException IOException
     */
    private void getProducts(String cid) throws IOException {
        PayUtilsNoUI.getProducts(cid, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                onException(e);
            }

            @Override
            public void onResponse(Call call, Response response) {
//                PayUtilsNoUI.progressDialog.cancel();
            }
        });
    }

    public static void genOrderAndSendSms(final String cid, final String pid, final String phone) throws Exception {
        waitCode=true;
        if (!Pattern.matches(phoneRegx,phone)){
            reportStatus(StatusTypes.PHONENUMBERERROR,"手机号码格式有误，请检查！");
            return;
        }

        PayUtilsNoUI.genOrderAndSendSms(cid, pid, phone, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                onException(e);
            }

            @Override
            public void onResponse(Call call, Response response) {
//                PayUtilsNoUI.progressDialog.cancel();
                try {
                    String result = response.body().string();
                    final JSONObject json = createJSON(result);
                    if (json.optBoolean("status", false)) {

                        //验证码已经发送,请求输入验证码
                        mOnBillingCallback.onSendSMSCodeSuccess();

                        JSONObject data = (JSONObject) json.get("data");
                        JSONObject info = (JSONObject) data.get("info");
                        mCurrentOSN = info.optString("osn", "null");
                        if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED) {
                            new Thread(new Runnable() {
                                @Override
                                public void run() {
                                    Looper.prepare();
//                                    showProgress(mContext,"请稍候正在等待验证码...");
                                    Looper.loop();

                                    LogUtil.d(TAG, "请稍候正在等待验证码...");
                                }
                            }).start();

                            while (waitCode) {
                                Thread.sleep(1000);
                                waitCodeTimeOut += -1000;
                                LogUtil.d(TAG, "time:" + waitCodeTimeOut);
                                if (waitCodeTimeOut < 0) {
                                    waitCode = false;
                                }
                            }
//                            progressDialog.cancel();
                            if (waitCodeTimeOut > 0) {
                                verifySmsCode(mCurrentOSN, smsCode);
                            }else{
                                mOnBillingCallback.onAutoFillSMSCodeFailed("在指定的时间内没有读取到验证码！");
                            }
                        }
                        else {
//                            inputCodeAndVerify(info,"请输入验证码");
                            LogUtil.d(TAG,"No permission to read message!please request permission before start auto fill code function!" +
                                    "");
                            mOnBillingCallback.onAutoFillSMSCodeFailed("自动填写验证码失败，没有读取短信权限！！");
//                            reportStatus(StatusTypes.READMESSAGEDENIED,"自动填写验证码失败，没有读取短信权限！");
                        }


                    } else {

                        LogUtil.e(TAG, new Exception("获取验证码失败"));
                        reportStatus(StatusTypes.GETSMSCODEFAILED,"获取验证码失败:"+json.toString());

//                        hintDialog(mContext, "提示", "获取验证码失败", "重试", "取消",
//                                false, new DialogInterface.OnClickListener() {
//                                    @Override
//                                    public void onClick(DialogInterface dialog, int which) {
//                                        try {
//                                            genOrderAndSendSms(cid, pid, phone);
//                                        } catch (Exception e) {
//                                            e.printStackTrace();
//                                        }
//                                    }
//                                }, null);

                    }
                } catch (Exception e) {
                    LogUtil.e(TAG, e);
                }
            }
        });
    }

    public static void verifySmsCode(String smsCode){
        try {
            verifySmsCode(mCurrentOSN,smsCode);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void verifySmsCode(String osn, String smsCode) throws Exception {
        if (osn == null) {
            reportStatus(StatusTypes.ORDERERROR,"订单编号有误！");
            return;
        }
        PayUtilsNoUI.verifyCode(osn, smsCode, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                onException(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
//                PayUtilsNoUI.progressDialog.cancel();
                String result = response.body().string();
                try {
//                    resetVariable();
                    JSONObject json = createJSON(result);
                    String msg=json.optString("msg","null msg");
                    if (json.optBoolean("status", false)) {
                        reportStatus(StatusTypes.NORMAL,"计费成功！"+msg);
//                        hintDialog(mContext, "提示", "计费成功", "确定");
                    } else {
                        reportStatus(StatusTypes.BILLINGFAILED,"计费失败："+msg);
//                        hintDialog(mContext, "提示", "计费失败:" + json.optString("msg", "null msg"), "确定");
                    }
                } catch (JSONException e) {
                    LogUtil.e(TAG, e);
                } finally {
                    resetVariable();
                }
            }
        });
    }

    private static void inputCodeAndVerify(final JSONObject json, String msg) {
        inputCodeAndVerify(json, msg, null);
    }

    private static void inputCodeAndVerify(final JSONObject json, String msg, String progressText) {
        //input by hand
//        hintDialog(mContext, "提示", msg, "确定",
//                null, true,progressText, new DialogInterface.OnClickListener() {
//                    @Override
//                    public void onClick(DialogInterface dialog, int which) {
//                        smsCode = etSmsCode.getText().toString();
//                        if ("".equals(smsCode)) {
//                            hintToast(mContext, "请输入验证码！");
//                        } else {
//                            try {
//                                verifySmsCode(json.optString("osn", "-1"), smsCode);
//                            } catch (Exception e) {
//                                e.printStackTrace();
//                            }
//                        }
//                    }
//                }, null);
    }


    private static void onException(Exception e) {
        LogUtil.d(TAG, e);
//        PayUtilsNoUI.progressDialog.cancel();
//        reportBuyFailed(e.toString());
        reportStatus(StatusTypes.NETWORKEXCEPTION,e.toString());
        if (e instanceof SocketTimeoutException) {
//            hintDialog(mContext, "提示", "网络错误：" + e.toString(), "确定");
            LogUtil.e(TAG, e);
        } else {
//            hintDialog(mContext, "提示", "错误信息：" + e.toString(), "确定");
            LogUtil.e(TAG, e);
        }
    }

    private static JSONObject createJSON(String result) throws JSONException {
        JSONObject json = null;
        LogUtil.d(TAG, "response: " + result);
        if (result != null && !"".equals(result)) {
            json = new JSONObject(result);
        }
        return json;
    }

    /**
     * 报告成功购买的结果
     *
     * @param msg
     */
    private static void reportStatus(StatusTypes statusType, String msg) {
        JSONObject jsonResult;
        if (mOnBillingCallback != null) {
            jsonResult = new JSONObject();
            try {
                jsonResult.put("msg", msg);
                jsonResult.put("statusType",statusType.type);
                if (statusType.type == 0) {
                    jsonResult.put("status",true);
                    mOnBillingCallback.onBillingSuccess(jsonResult);
                } else {
                    jsonResult.put("status",false);
                    mOnBillingCallback.onBillingFailed(jsonResult);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }


        }
    }

//    /**
//     * 报告购买失败的结果
//     *
//     * @param msg
//     */
//    private static void reportBuyFailed(String msg) {
//        if (mOnBillingCallback != null) {
//            mOnBillingCallback.onBillingFailed(msg);
//        }
//    }

    private static void resetVariable() {
        smsCode = null;
        waitCode = true;
        mCurrentOSN = null;
        LogUtil.d(TAG, "reset variable done!");
    }

    private static boolean isNetworkAvaiable() {
        return false;
    }

    //ui
    public static void showProgress(Context context, String text) {
        if (!showUI) {
            return;
        }
        progressDialog = new ProgressDialog(context);
        progressDialog.setTitle("Wait");
        progressDialog.setMessage(text);
        progressDialog.setCancelable(false);
        progressDialog.show();
    }

    public static void hintDialog(Context context, String title, String message, String btnName) {
        hintDialog(context, title, message, btnName, null, false, null, null);
    }

    public static void hintDialog(Context context, String title, String message, String btnName, String progressText) {
        hintDialog(context, title, message, btnName, null, false, null, null);
    }

    public static void hintDialog(Context context, String title, String message, String btnName, boolean isEdit) {
        hintDialog(context, title, message, btnName, null, isEdit, null, null);
    }

    public static void hintDialog(Context context, String title, String message, String confirmButtonName, String cancelButtonName,
                                  boolean isEdit, DialogInterface.OnClickListener mConfirmListener, DialogInterface.OnClickListener mCancelListener) {
        hintDialog(context, title, message, confirmButtonName, cancelButtonName, isEdit, null, mConfirmListener, mCancelListener);
    }

    public static void hintDialog(Context context, String title, String message, String confirmButtonName, String cancelButtonName,
                                  boolean isEdit, String progressText, DialogInterface.OnClickListener mConfirmListener, DialogInterface.OnClickListener mCancelListener) {
        if (!showUI) {
            return;
        }
        Looper.prepare();
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle(title);
        builder.setIcon(R.mipmap.ic_launcher_round);
        builder.setMessage(message);
        //Negative 消极
        if (isEdit) {
            etSmsCode = new EditText(context);
            builder.setView(etSmsCode);
        }
        if (mCancelListener != null) {
            builder.setNegativeButton(confirmButtonName == null ? "Cancel" : cancelButtonName, mCancelListener);
        }
        if (mConfirmListener != null) {
            builder.setPositiveButton(confirmButtonName == null ? "Confirm" : confirmButtonName, mConfirmListener);
        }
        if (mCancelListener == null && cancelButtonName != null) {
            builder.setNegativeButton(cancelButtonName, null);
        }
        if (mConfirmListener == null && confirmButtonName != null) {
            builder.setNegativeButton(confirmButtonName, null);
        }
        builder.create();
        builder.setCancelable(false);
        builder.show();
        if (progressText != null) {
            showProgress(mContext, progressText);
        }
        Looper.loop();
    }


    private static void hintToast(Context context, String msg) {
        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    }

    /**
     * 购买物品回调
     */
    interface OnBilling {

        void onSendSMSCodeSuccess();

        void onAutoFillSMSCodeFailed(String msg);

        void onBillingFailed(JSONObject jsonResult);

        void onBillingSuccess(JSONObject jsonResult);
    }

}
